from typing import Union
from ...addon.naming import FluidLabNaming
from .common_list_methods import FLUIDLAB_CommonList
from ...libs.functions.get_common_vars import get_common_vars
from bpy.types import PropertyGroup, UIList, Collection, Object
from .props_list_fluid_emitters import FluidEmittersList, FluidEmittersListItem
from ...libs.functions.collections import remove_collection, remove_collection_if_is_empty
from bpy.props import StringProperty, IntProperty, CollectionProperty, BoolProperty, PointerProperty, EnumProperty



""" Fluids Groups List """


class FLUIDLAB_UL_draw_fluids_groups(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        
        if not item.id_name or not item.group_coll:
            layout.prop(item, "remove", text="Clear", icon='X')
            return
        
        main_modules = context.scene.fluidlab.ui.main_modules
        wm = context.window_manager

        left_sect = layout.row(align=True)

        # si estoy en mis paneles o en el panel Mesh (ya que el panel mesh lanza el popup):
        if context.region.type == 'UI' or main_modules == 'MESH':
            left_sect.label(text="", icon='OUTLINER_COLLECTION')

        if context.region.type == 'WINDOW':

            if FluidLabNaming.WM_BAKE_POPUP_OPENED in wm:

                # CUANDO SON POPUPS DE BAKE:
                left_sect.separator()
                left_sect.prop(item, "bakeme", text="")
            
            else:

                # --- El resto de popups --- #

                # Cuando etoy en modo popup, (el Fluid interactions popup), muestro los cehckbox de interactive:
                if main_modules == 'FLUID_INTERACTIONS':
                    left_sect.separator()
                    left_sect.prop(item, "interactive", text="")
                
                # Cuando etoy en modo popup, (el Add Mesh popup), muestro los cehckbox de meshme:
                if main_modules == 'MESH':
                    left_sect.separator()
                    left_sect.prop(item, "meshme", text="")
            

        # Cuando estoy y no estoy en popups:
        # left_sect.prop(item, "label_txt", text="", emboss=False)
        left_sect.prop(item.group_coll, "name", text="", emboss=False)

        # Cuando NO etoy en modo popup:
        if context.region.type == 'UI':

            # Right Section:
            right_sect = left_sect.row(align=True)
            right_sect.alignment = 'RIGHT'
            
            # Visible icon:
            right_sect.prop(item, "visible", text="", icon='HIDE_OFF' if item.visible else 'HIDE_ON', emboss=False)

            # Enabled icon:
            right_sect.prop(item, "enable", text="", icon='RESTRICT_VIEW_OFF' if item.enable else 'RESTRICT_VIEW_ON', emboss=False)

            # Remove icon:
            rm_button = right_sect.row(align=True)
            rm_button.alert = True
            rm_button.prop(item, "remove", text="", emboss=False, icon='X')

class FluidGroups_StoredKeyFrames(PropertyGroup):
    keyframe: IntProperty(default=-1)


class FluidGroupsListItem(PropertyGroup):
    label_txt: StringProperty(name="Name")
    id_name: StringProperty(name="ID")
    emitters: PointerProperty(type=FluidEmittersList)
    
    group_coll: PointerProperty(type=Collection)
    vertex_coll: PointerProperty(type=Collection)
    mesh_coll: PointerProperty(type=Collection)

    # Guardo los keyframes:
    soft_start_keyframes: CollectionProperty(type=FluidGroups_StoredKeyFrames)
    def soft_start_add_frame(self, kf:int):
        # Prevent store frames already stored:
        if not any(kf_item.keyframe == kf for kf_item in self.soft_start_keyframes):
            item = self.soft_start_keyframes.add()
            item.keyframe = kf
    
    @property
    def get_soft_start_keyframes(self):
        return [k.keyframe for k in self.soft_start_keyframes]
    
    @property
    def clear_soft_start_keyframes(self):
        self.soft_start_keyframes.clear()
    
    # Guardo los keyframes:
    soft_end_keyframes: CollectionProperty(type=FluidGroups_StoredKeyFrames)
    def soft_end_add_frame(self, kf:int):
        # Prevent store frames already stored:
        if not any(kf_item.keyframe == kf for kf_item in self.soft_end_keyframes):
            item = self.soft_end_keyframes.add()
            item.keyframe = kf
    
    @property
    def get_soft_end_keyframes(self):
        return [k.keyframe for k in self.soft_end_keyframes]
    
    @property
    def clear_soft_end_keyframes(self):
        self.soft_end_keyframes.clear()

    emitter_type: EnumProperty(
        items=[
            ('GEOMETRY',    "Geometry", "", 0),
            ('INFLOW',      "InFlow",   "", 1),
            ('OUTFLOW',     "OutFlow",  "", 2)
        ],
        default='GEOMETRY'
    )
        
    def do_remove(self, context):
        
        fluid_groups = get_common_vars(context, get_fluid_groups=True)

        # Si no esta vacio
        if not self.emitters.is_void:

            # Primero elimino los emitters:
            for i in reversed(range(self.emitters.length)):
                self.emitters.list_index = i
                self.emitters.active.remove = True
                self.emitters.list_index = 0
            
        # Eliminamos la collection:
        remove_collection(context, self.group_coll, False)

        # Lo quitamos del listado:
        fluid_groups.remove_item(self.id_name)
        fluid_groups.list_index = fluid_groups.length-1 if not fluid_groups.is_void else 0 
    
        remove_collection_if_is_empty(context, FluidLabNaming.FLUID_GROUPS_COLL)
        remove_collection_if_is_empty(context, FluidLabNaming.FluidLab)

    remove: BoolProperty(
        default=False, 
        update=do_remove
    )

    def visible_update(self, context):

        emitters = self.emitters.get_all_items
        for item in emitters:
            item.visible = self.visible

    visible: BoolProperty(
        default=True, 
        update=visible_update
    )

    def enable_update(self, context):

        emitters = self.emitters.get_all_items
        for e in emitters:
            e.enable = self.enable

    enable: BoolProperty(
        default=True, 
        update=enable_update
    )

    def interactive_update(self, context):

        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        item = fluid_groups.get_item_from_id(self.id_name)

        emitters = item.emitters.get_all_items
        for e in emitters:
            e.interactive = self.interactive

    # para cuando muestro el popup de Fluid interactions:
    interactive: BoolProperty(
        default=True, 
        update=interactive_update
    )

    # Para el popup de mesh (remesh):
    def meshme_update(self, context):
        emitters_list = self.emitters
        all_emitters_items = emitters_list.get_all_items
        for item in all_emitters_items:
            item.meshme = self.meshme

    meshme: BoolProperty(default=True, update=meshme_update)

    # para el popup de bake:
    def bake_update(self, context):

        fluid_groups = get_common_vars(context, get_fluid_groups=True)
        item = fluid_groups.get_item_from_id(self.id_name)

        emitters = item.emitters.get_all_items
        for e in emitters:
            e.bakeme = self.bakeme

    bakeme: BoolProperty(
        default=False,
        update=bake_update
    )
    

class FluidGroupList(PropertyGroup, FLUIDLAB_CommonList):

    # Attributes (with or without methods):
    def list_index_update(self, context):
        item = self.active
        if not item:
            return
        pass
    
    list_index: IntProperty(name="Layer List", description="The Layer List", default=-1, update=list_index_update)
    list: CollectionProperty(type=FluidGroupsListItem)


    # Fluid Groups List Methods:
    def add_item(self, item_id:str, label_txt:str, group_coll:Collection, emitter_type:str, vertex_coll:Collection=None, prev_size:float=None) -> FluidGroupsListItem:

        item = self.list.add()
        item.id_name = item_id
        item.label_txt = label_txt
        item.group_coll = group_coll
        item.emitter_type = emitter_type

        # Al duplicar el grupo, le seteamos el vertex_coll que habíamos guardado previamente:
        if vertex_coll:
            item.vertex_coll = vertex_coll

        # Al duplicar el grupo, le seteamos el prev_size que habíamos guardado previamente:
        if prev_size:
            item.prev_size = prev_size
        
        # seteamos el ultimo elemento como activo:
        self.list_index = self.length-1

        return item
    
    # @property
    # def get_all_emitter_from_all_groups(self):
    #     all_group_items = self.get_all_items
    #     return list(set(emitter for g_item in all_group_items if g_item.use_colliders for emitter in g_item.emitters.get_all_emitters))

    #-------------------------------------------------------------------------------------------------------------------------------------- 
    # Para recuperar los datos de ui en modo local o global:
    
    def get_first_global_emitter(self, section_props:str=None, without_self_ob:bool=False, target:str="object", debug:bool=False) -> Union[Object, FluidEmittersListItem]:

        if section_props is None:
            return
        
        active_group = self.active 
        active_emitter_item = active_group.emitters.active
        emitters_list = active_group.emitters 
        all_emitter_items = emitters_list.get_all_items 
        all_emitters = emitters_list.get_all_emitters
    
        if without_self_ob:
            id_name = next((emitter_item.id_name for emitter_item in all_emitter_items if getattr(emitter_item.switchers, section_props) and emitter_item != active_emitter_item), None)
        else:
            id_name = next((emitter_item.id_name for emitter_item in all_emitter_items if getattr(emitter_item.switchers, section_props)), None)
    
        if target == "object":
            emitter = next((ob for ob in all_emitters if ob.fluidlab.id_name == "Emitter_" + id_name ), None)
        
        elif target == "item":
            emitter = next((item for item in all_emitter_items if item.id_name == id_name), None)

        if debug:
            print(f"section_props: {section_props} target: {target} return {emitter}")

        return emitter
    
    
    # End Para recuperar los datos de ui en modo local o global.
    #-------------------------------------------------------------------------------------------------------------------------------------- 